package com.zk.shopping.user.service.impl;


import com.zk.shopping.base.model.ModelResult;
import com.zk.shopping.base.model.ReturnCodeEnum;
import com.zk.shopping.base.service.ISecurityService;
import com.zk.shopping.base.service.impl.BaseServiceImpl;
import com.zk.shopping.base.utils.*;
import com.zk.shopping.user.dao.IUserDao;
import com.zk.shopping.user.entity.UserEntity;
import com.zk.shopping.user.entity.UserStatusEnum;
import com.zk.shopping.user.service.IUserService;
import com.zk.shopping.userLog.entity.UserLogTypeEnum;
import com.zk.shopping.userLog.service.IUserLogService;
import nl.bitwalker.useragentutils.UserAgent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl extends BaseServiceImpl<IUserDao, UserEntity> implements IUserService {

    Log logger = LogFactory.getLog(UserServiceImpl.class);

    @Autowired
    private IUserLogService userLogService;

    @Autowired
    private ISecurityService securityService;

    @Value("${login.error.limited}")
    private int loginErrorLimited;


    // return code: [200-成功；1-用户名或者密码不能为空；2-用户名或者密码错误；3-账户已被冻结;4-密码错误次数太多，5-未找到密钥]
    @Override
    public ModelResult<UserEntity> login(HttpServletRequest request, String userId, String password) {
        logger.info("登陆请求[userId:" + userId + ",password:" + password + "]");
        ModelResult<UserEntity> reslt = new ModelResult<>("登陆成功");
        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(password)) {
            reslt.setCode(1);
            reslt.setMessage("用户名或者密码不能为空");
            return reslt;
        }
        //密码错误次数太多
        int limitTimeInsecond = getLoginLimitTimeInsecond(userId);
        if (limitTimeInsecond > 0) {
            reslt.setCode(4);
            reslt.setExtaData(limitTimeInsecond);
            reslt.setMessage("密码错误次数太多");
            return reslt;
        }

        Map<String, Object> reqParams = new HashMap<>();
        reqParams.put("userId", userId);
        List<UserEntity> userList = getList(reqParams);
        if (CollectionUtils.isEmpty(userList) || userList.size() != 1) {
            reslt.setCode(2);
            reslt.setMessage("用户名或者密码错误");
            return reslt;
        }
        UserEntity userInfo = userList.get(0);

        if (userInfo.getStatus() == UserStatusEnum.FROZEN.code) {
            reslt.setCode(3);
            reslt.setMessage("账户已被冻结");
            return reslt;
        }
        //解密
        ModelResult<String> decryptData = securityService.decrypt4RSA(userId, password);
        if (decryptData.getCode() != ReturnCodeEnum.REQUEST_SUCESS.code) {
            reslt.setCode(5);
            reslt.setMessage("未找到密钥");
            return reslt;
        }
        //解密后的密码
        String decryptPassword = decryptData.getData();
        if (!isRightPasswd(decryptPassword, userInfo)) {
            reslt.setCode(2);
            reslt.setMessage("用户名或者密码错误");
            userLogService.save("登陆失败", userInfo.getUserId(), userInfo.getUserName(), UserLogTypeEnum.LOGIN);
            //剩余重试错误
            recordLoginFailed(userId);
            int leftLoginNumber = getLeftLoginNumber(userId);
            reslt.setExtaData(leftLoginNumber);
            return reslt;
        }
        RedisClientUtils.del(Constants.REDIS_LOGIN_ERROR_NUMBER + userId);
        RedisClientUtils.del(Constants.REDIS_LOGIN_ERROR_LIMITED + userId);
        userInfo.setPassword(null);
        userInfo.setId(null);
        reslt.setData(userInfo);
        //处理session
        request.getSession().setAttribute("userInfo", userInfo);
        //threadlocal
        ThreadLocalUtils.addLoginUserEntity(userInfo);
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        ThreadLocalUtils.addLoginDevice(userAgent);
        //记录日志
        userLogService.save("登陆成功", userInfo.getUserId(), userInfo.getUserName(), UserLogTypeEnum.LOGIN);
        return reslt;
    }


    private boolean isRightPasswd(String decryptPassword, UserEntity userInfo) {
        boolean isRight = false;
        try {
            decryptPassword += DecimalFormatUtils.format(userInfo.getCreateAt() % 10000, "0000");
            isRight = MD5Utils.verify(decryptPassword, userInfo.getPassword());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("RSA解密失败" + e);
        }
        return isRight;
    }

    /**
     * 是否仍在登陆限制之中
     *
     * @param userId
     * @return
     */
    private int getLoginLimitTimeInsecond(String userId) {
        String redisKey = Constants.REDIS_LOGIN_ERROR_LIMITED + userId;
        if(RedisClientUtils.exists(redisKey)){
            return RedisClientUtils.ttl(redisKey);
        }else{
            return -1;
        }
    }

    /**
     * 登陆重试的次数
     * @param userId
     */
    private int getLeftLoginNumber(String userId) {
        String redisKey = Constants.REDIS_LOGIN_ERROR_NUMBER + userId;
        int wrongNumberAll = Integer.parseInt(RedisClientUtils.get(redisKey));
        int wrongNumber = wrongNumberAll % this.loginErrorLimited;
        int leftNumber = wrongNumber == 0  ? 0 : this.loginErrorLimited - wrongNumber;
        return leftNumber;
    }

    /**
     * 记录密码错误次数
     * @param userId
     */
    private void recordLoginFailed(String userId) {
        String redisKey = Constants.REDIS_LOGIN_ERROR_NUMBER + userId;
        if(!RedisClientUtils.exists(redisKey)){
            RedisClientUtils.set(redisKey, "1");
        }else{
            RedisClientUtils.incr(redisKey);
        }
        int wrongNumberAll = Integer.parseInt(RedisClientUtils.get(redisKey));
        if(wrongNumberAll  % this.loginErrorLimited == 0){
            int limitNumber = wrongNumberAll / this.loginErrorLimited;
            RedisClientUtils.setex(Constants.REDIS_LOGIN_ERROR_LIMITED + userId, (int) (Math.pow(2, limitNumber) * 300), "1");
        }
    }


    @Override
    public ModelResult<String> logout(HttpServletRequest request) {
        ModelResult<String> reslt = new ModelResult<>("登出成功");
        request.getSession().invalidate();
        ThreadLocalUtils.removeLoginDevice();
        ThreadLocalUtils.removeLoginUserEntity();
        return reslt;
    }

    // return code: [200-成功；1-userId为空；2-用户不存在；]
    @Override
    public ModelResult<UserEntity> getByUserId(String userId) {
        ModelResult<UserEntity> result = new ModelResult<>("查询成功");
        if (StringUtils.isEmpty(userId)) {
            result.setCode(1);
            result.setMessage("userId为空");
            return result;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        List<UserEntity> userList = getList(params);
        if (CollectionUtils.isEmpty(userList) || userList.size() != 1) {
            result.setCode(2);
            result.setMessage("用户不存在");
            return result;
        }
        result.setData(userList.get(0));
        return result;
    }

    // return code: [200-成功；1-userId为空；2-用户不存在；3-正常用户才可以冻结;4-已冻结用户才可以冻结;5-状态状态未知;]
    @Override
    public ModelResult<String> changeStatus(String userId, Integer status) {
        ModelResult<String> result = new ModelResult<>("修改成功");
        ModelResult<UserEntity> userEntityModelReslt = getByUserId(userId);
        if (userEntityModelReslt.getCode() != ReturnCodeEnum.REQUEST_SUCESS.code) {
            result.setCode(userEntityModelReslt.getCode());
            result.setMessage(userEntityModelReslt.getMessage());
            return result;
        }
        UserEntity userEntity = userEntityModelReslt.getData();
        int orgStatus = userEntity.getStatus();
        //校验
        if (UserStatusEnum.getByCode(status) == null) {
            result.setCode(5);
            result.setMessage("状态未知");
            return result;
        }
        if (status.equals(UserStatusEnum.FROZEN.code) && !userEntity.getStatus().equals(UserStatusEnum.NORMAL.code)) {
            result.setCode(3);
            result.setMessage("正常用户才可以冻结");
            return result;
        } else if (status.equals(UserStatusEnum.NORMAL.code) && !userEntity.getStatus().equals(UserStatusEnum.FROZEN.code)) {
            //解冻
            result.setCode(4);
            result.setMessage("已冻结用户才可以冻结");
            return result;
        }
        userEntity.setStatus(status);
        modifyById(userEntity);
        String logMsg = "修改状态（" + UserStatusEnum.getByCode(orgStatus).name + "->" + UserStatusEnum.getByCode(status).name + "）";
        userLogService.save(logMsg, userEntity.getUserId(), userEntity.getUserName(), UserLogTypeEnum.UPDATE);
        return result;
    }

    // return code: [200-成功；1-用户不存在；]
    @Override
    public ModelResult<String> update(UserEntity userEntity) {
        ModelResult<String> result = new ModelResult<>("修改成功");
        UserEntity dbUserEntity = get(userEntity.getId());
        if (dbUserEntity == null) {
            result.setCode(1);
            result.setMessage("用户不存在");
            return result;
        }
        modifyById(userEntity);
        String logMsg = "修改用户信息";
        userLogService.save(logMsg, dbUserEntity.getUserId(), dbUserEntity.getUserName(), UserLogTypeEnum.UPDATE);
        return result;
    }

    // return code: [200-成功；1-用户ID为空；2-用户ID已存在]
    @Override
    public ModelResult<UserEntity> create(UserEntity userEntity) {
        ModelResult<UserEntity> result = new ModelResult<>("创建成功");
        ModelResult<UserEntity> userEntityModelReslt = getByUserId(userEntity.getUserId());
        //用户ID为空
        if (userEntityModelReslt.getCode() == 1) {
            result.setCode(userEntityModelReslt.getCode());
            result.setMessage(userEntityModelReslt.getMessage());
            return result;
        }
        //用户ID已存在
        if (userEntityModelReslt.getCode() == 200) {
            result.setCode(2);
            result.setMessage("用户ID已存在");
            return result;
        }
        //默认密码
        userEntity.setPassword("123456");
        super.create(userEntity);
        //记录日志
        String logMsg = "新增用户";
        userLogService.save(logMsg, userEntity.getUserId(), userEntity.getUserName(), UserLogTypeEnum.CREATE);

        return result;
    }


}


